package com.eian.boot.crypto.utils;

import com.eian.boot.crypto.constant.CryptoConstants;
import com.eian.boot.crypto.enums.CryptoAlgorithm;
import com.eian.boot.crypto.exception.KeyException;
import com.eian.boot.crypto.model.KeyPairInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 密钥工具类
 *
 * @author eian
 */
public class KeyUtils {

    static {
        // 注册 BouncyCastle 提供者（支持国密算法）
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    private KeyUtils() {
    }

    /**
     * 生成对称密钥
     *
     * @param algorithm 算法
     * @param keySize   密钥长度（位）
     * @return Base64编码的密钥
     */
    public static String generateSymmetricKey(CryptoAlgorithm algorithm, int keySize) {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(
                    algorithm.getAlgorithmName(),
                    algorithm.isGM() ? CryptoConstants.Provider.BOUNCY_CASTLE : CryptoConstants.Provider.SUN_JCE
            );
            keyGenerator.init(keySize);
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64Utils.encode(secretKey.getEncoded());
        } catch (Exception e) {
            throw new KeyException("生成对称密钥失败: " + algorithm.getAlgorithmName(), e);
        }
    }

    /**
     * 生成 AES 密钥
     *
     * @param keySize 密钥长度（128/192/256）
     * @return Base64编码的密钥
     */
    public static String generateAESKey(int keySize) {
        return generateSymmetricKey(CryptoAlgorithm.AES_CBC, keySize);
    }

    /**
     * 生成 SM4 密钥
     *
     * @return Base64编码的密钥
     */
    public static String generateSM4Key() {
        return generateSymmetricKey(CryptoAlgorithm.SM4_CBC, CryptoConstants.KeySize.SM4_128);
    }

    /**
     * 生成非对称密钥对
     *
     * @param algorithm 算法
     * @param keySize   密钥长度（位）
     * @return 密钥对信息
     */
    public static KeyPairInfo generateKeyPair(CryptoAlgorithm algorithm, int keySize) {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
                    algorithm.getAlgorithmName(),
                    algorithm.isGM() ? CryptoConstants.Provider.BOUNCY_CASTLE : CryptoConstants.Provider.SUN_RSA_SIGN
            );
            keyPairGenerator.initialize(keySize);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            return KeyPairInfo.builder()
                    .publicKey(Base64Utils.encode(keyPair.getPublic().getEncoded()))
                    .privateKey(Base64Utils.encode(keyPair.getPrivate().getEncoded()))
                    .algorithm(algorithm.getAlgorithmName())
                    .keySize(keySize)
                    .build();
        } catch (Exception e) {
            throw new KeyException("生成密钥对失败: " + algorithm.getAlgorithmName(), e);
        }
    }

    /**
     * 生成 RSA 密钥对
     *
     * @param keySize 密钥长度（1024/2048/4096）
     * @return 密钥对信息
     */
    public static KeyPairInfo generateRSAKeyPair(int keySize) {
        return generateKeyPair(CryptoAlgorithm.RSA, keySize);
    }

    /**
     * 生成 SM2 密钥对
     *
     * @return 密钥对信息
     */
    public static KeyPairInfo generateSM2KeyPair() {
        return generateKeyPair(CryptoAlgorithm.SM2, CryptoConstants.KeySize.SM2_256);
    }

    /**
     * Base64编码的密钥字符串转对称密钥对象
     *
     * @param keyStr    Base64编码的密钥
     * @param algorithm 算法名称
     * @return SecretKey对象
     */
    public static SecretKey toSecretKey(String keyStr, String algorithm) {
        try {
            byte[] keyBytes = Base64Utils.decode(keyStr);
            return new SecretKeySpec(keyBytes, algorithm);
        } catch (Exception e) {
            throw new KeyException("转换对称密钥失败", e);
        }
    }

    /**
     * Base64编码的公钥字符串转公钥对象
     *
     * @param publicKeyStr Base64编码的公钥
     * @param algorithm    算法名称
     * @return PublicKey对象
     */
    public static PublicKey toPublicKey(String publicKeyStr, String algorithm) {
        try {
            byte[] keyBytes = Base64Utils.decode(publicKeyStr);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(
                    algorithm,
                    isGMAlgorithm(algorithm) ? CryptoConstants.Provider.BOUNCY_CASTLE : CryptoConstants.Provider.SUN_RSA_SIGN
            );
            return keyFactory.generatePublic(keySpec);
        } catch (Exception e) {
            throw new KeyException("转换公钥失败", e);
        }
    }

    /**
     * Base64编码的私钥字符串转私钥对象
     *
     * @param privateKeyStr Base64编码的私钥
     * @param algorithm     算法名称
     * @return PrivateKey对象
     */
    public static PrivateKey toPrivateKey(String privateKeyStr, String algorithm) {
        try {
            byte[] keyBytes = Base64Utils.decode(privateKeyStr);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(
                    algorithm,
                    isGMAlgorithm(algorithm) ? CryptoConstants.Provider.BOUNCY_CASTLE : CryptoConstants.Provider.SUN_RSA_SIGN
            );
            return keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            throw new KeyException("转换私钥失败", e);
        }
    }

    /**
     * 生成随机初始化向量（IV）
     *
     * @param size IV长度（字节）
     * @return Base64编码的IV
     */
    public static String generateIV(int size) {
        byte[] iv = new byte[size];
        new SecureRandom().nextBytes(iv);
        return Base64Utils.encode(iv);
    }

    /**
     * 判断是否是国密算法
     */
    private static boolean isGMAlgorithm(String algorithm) {
        return CryptoConstants.Algorithm.SM2.equals(algorithm) || CryptoConstants.Algorithm.SM4.equals(algorithm);
    }
}

